package com.yingsheng.bi.hks.template.service;

import com.yingsheng.bi.hks.template.annotation.Context2Request;
import com.yingsheng.bi.hks.template.annotation.Context2Response;
import com.yingsheng.bi.hks.template.annotation.RequestContextMode;
import com.yingsheng.bi.hks.template.annotation.Response2Context;
import com.yingsheng.bi.hks.template.events.Event;
import com.yingsheng.bi.hks.template.utils.JacksonUtils;
import com.yingsheng.bi.hks.template.utils.TemplateContext;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

public class ContextMethodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Event event = TemplateContext.getRequestContext().getEvent();
        if (event != null) {
            Map<String, Object> parentContext = event.getDataMap();
            try {
                Method method = invocation.getMethod();
                Parameter[] parameters = method.getParameters();
                Object[] arguments = invocation.getArguments();
                Map<String, Object> currentContext = new HashMap<>();
                for (int i = 0; i < parameters.length; i++) {
                    if (arguments[i] != null && parameters[i].isAnnotationPresent(Context2Request.class)) {
                        Context2Request context2Request = parameters[i].getAnnotation(Context2Request.class);
                        Map<String, Object> dataContext = new HashMap<>();
                        dataContext.putAll(parentContext);
                        dataContext.putAll(JacksonUtils.obj2Map(arguments[i]));
                        arguments[i] = JacksonUtils.map2Obj(dataContext, arguments[i].getClass());
                        if (RequestContextMode.DEFAULT == context2Request.mode() || RequestContextMode.CURR == context2Request.mode()) {
                            dataContext = JacksonUtils.obj2Map(arguments[i]);
                            if (!CollectionUtils.isEmpty(dataContext)) {
                                currentContext.putAll(dataContext);
                            }
                        }
                    }
                }
                event.setDataMap(currentContext);
                Object returnValue = invocation.proceed();
                if (returnValue != null) {
                    Response2Context response2Context = AnnotationUtils.findAnnotation(method, Response2Context.class);
                    if (response2Context != null) {
                        Map<String, Object> returnMap = JacksonUtils.obj2Map(returnValue);
                        parentContext.putAll(returnMap);
                        Context2Response context2Response = AnnotationUtils.findAnnotation(method, Context2Response.class);
                        if (context2Response != null) {
                            currentContext.putAll(returnMap);
                            Object result = JacksonUtils.map2Obj(currentContext, returnValue.getClass());
                            if (result != null) {
                                return result;
                            }
                        }
                    }
                }
                return returnValue;
            } finally {
                event.setDataMap(parentContext);
            }
        } else {
            return invocation.proceed();
        }
    }
}
